package com.itttq.gen.generator;

import com.itttq.gen.common.conf.GenProperties;
import com.itttq.gen.common.constant.Constants;
import com.itttq.gen.common.constant.StatusTypeEnums;
import com.itttq.gen.generator.to.GeneratorTo;
import com.itttq.gen.model.po.ProjectPo;
import com.itttq.gen.utils.StringUtil;
import freemarker.template.Configuration;
import freemarker.template.Template;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import java.io.*;
import java.util.List;

/**
 * 使用Freemarker模板生成文件
 *
 * @author Administrator
 */
@Component
public class GenProject {
    public static final String JAVA_DIR = "src/main/java/";
    public static final String NAME_APPLICATION = "Application.java";
    public static final String NAME_MAPPER = "Mapper.java";
    /**
     * 占位符，会在实际生成文件过程中被替换为实体类名称
     */
    public static final String PLACEHOLDER = "@@@";
    public static final String FILE_REDIS_UTIL = "RedisUtil.java";

    @Autowired
    private GenProperties genPropes;

    public void genByProjectDir(ProjectPo project) throws IOException {
        List<GeneratorTo> generators = TableInfo.getTableInfo(project);
        if (generators.isEmpty()) {
            return;
        }

        Configuration configuration = new Configuration(Configuration.VERSION_2_3_21);
        // 代码目录路径：如 src/main/java/
        File tmplDir = new File(genPropes.getTmplProjectFlord());
        configuration.setDirectoryForTemplateLoading(tmplDir);
        genByProjectDir(project, configuration, tmplDir);

        tmplDir = new File(genPropes.getTmplGeneratorFlord());
        configuration.setDirectoryForTemplateLoading(tmplDir);
        genByGeneratorDir(project, generators, configuration, tmplDir);
    }

    /**
     * 获取生成文件的最顶级：配置的生成项目文件路径 + 项目ID
     *
     * @param project
     * @return
     */
    public String getParentPath(ProjectPo project) {
        return genPropes.getProjectDir() + project.getCreator() + Constants.SLASH;
    }

    /**
     * 获取项目文件夹地址，在项目父目录下新建一个项目code命名的文件夹
     * @param project
     * @return
     */
    public String getProjectPath(ProjectPo project) {
        return getParentPath(project)  + project.getCode() + Constants.SLASH;
    }

    /**
     * 循环读取只需要项目配置就能生成的文件
     *
     * @param project 项目配置信息
     * @param conf    模板配置信息
     * @param file    文件或文件目录
     * @throws IOException
     */
    private void genByProjectDir(ProjectPo project, Configuration conf, File file) throws IOException {
        String tmplPath;
        String filePath;
        for (File f : file.listFiles()) {
            if (f.isDirectory()) {
                genByProjectDir(project, conf, f);
            } else {
                if (FILE_REDIS_UTIL.equals(f.getName()) && StatusTypeEnums.StatusEnums.ENABLE.getCode() != project.getRedisEnable().intValue()) {
                    continue;
                }
                tmplPath = f.getCanonicalPath().replaceAll("\\\\", "/").replace(genPropes.getTmplProjectFlord(), "");
                filePath = tmplPath.replace(JAVA_DIR, JAVA_DIR + project.getPackagePath().replaceAll("\\.", Constants.SLASH) + Constants.SLASH);
                if (NAME_APPLICATION.equals(f.getName())) {
                    filePath = filePath.replace(NAME_APPLICATION, StringUtil.capitalize(project.getApplicationCode()) + NAME_APPLICATION);
                }
                generateByProjectPo(project, conf.getTemplate(tmplPath), getProjectPath(project) + filePath);
            }
        }
    }

    /**
     * 循环读取只需要项目配置就能生成的文件
     *
     * @param project 项目配置信息
     * @param conf    模板配置信息
     * @param file    文件或文件目录
     * @throws IOException
     */
    private void genByGeneratorDir(ProjectPo project, List<GeneratorTo> generators, Configuration conf, File file) throws IOException {
        String tmplPath;
        String filePath;
        for (File f : file.listFiles()) {
            if (f.isDirectory()) {
                genByGeneratorDir(project, generators, conf, f);
            } else {
                tmplPath = f.getCanonicalPath().replaceAll("\\\\", "/").replace(genPropes.getTmplGeneratorFlord(), "");
                filePath = tmplPath.replace(JAVA_DIR, JAVA_DIR + project.getPackagePath().replaceAll("\\.", Constants.SLASH) + Constants.SLASH);
                if (NAME_MAPPER.equals(f.getName())) {
                    filePath = filePath.replace(f.getName(), "I" + PLACEHOLDER + f.getName());
                } else {
                    filePath = filePath.replace(f.getName(), PLACEHOLDER + f.getName());
                }
                generateByGenerators(generators, conf.getTemplate(tmplPath), getProjectPath(project) + filePath);
            }
        }
    }

    /**
     * 根据ProjectPo对象生成文件
     *
     * @param project 项目对象
     * @param tmpl    模板对象
     * @param path    生成文件路径
     * @return 生成成功返回true，生成失败返回false
     */
    private static boolean generateByProjectPo(ProjectPo project, Template tmpl, String path) {
        StringWriter stringWriter = null;
        boolean rs = true;
        try {
            stringWriter = new StringWriter();
            tmpl.process(project, stringWriter);
            // 生成Po文件
            createFile(stringWriter.toString(), path);
        } catch (Exception e) {
            e.printStackTrace();
            rs = false;
        } finally {
            closeStringWriter(stringWriter);
        }
        return rs;
    }


    /**
     * 根据GeneratorTo集合生成文件
     *
     * @param generators Generator对象
     * @param tmpl       模板对象
     * @param path       生成文件路径
     * @return 生成成功返回true，生成失败返回false
     */
    public static boolean generateByGenerators(List<GeneratorTo> generators, Template tmpl, String path) {
        StringWriter out = null;
        boolean rs = true;
        for (GeneratorTo generator : generators) {
            try {
                out = new StringWriter();
                tmpl.process(generator, out);
                // 生成Po文件
                createFile(out.toString(), path.replace(PLACEHOLDER, StringUtil.capitalize(generator.getAlias())));
            } catch (Exception e) {
                e.printStackTrace();
                rs = false;
                break;
            } finally {
                closeStringWriter(out);
            }
        }
        return rs;
    }

    private static void closeStringWriter(StringWriter stringWriter) {
        try {
            if (null != stringWriter) {
                stringWriter.close();
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    public static void createFile(String content, String filePath) throws Exception {
        if (filePath.contains(Constants.DOT)) {
            //得到写文件路径
            File file = new File(filePath.substring(0, filePath.lastIndexOf(Constants.SLASH)));
            //如果目录不存在，则创建目录
            if (!file.exists()) {
                file.mkdirs();
            }
        }
        //写文件
        OutputStreamWriter out = null;
        try {
            out = new OutputStreamWriter(new FileOutputStream(filePath), "utf-8");
            out.write(content);
            out.flush();
        } finally {
            if (out != null) {
                out.close();
            }
        }
    }

}
